package pt.um.jspecput.lib.writer;

import static pt.um.jspecput.util.Constants.*;

import java.io.IOException;
import java.io.Writer;

/**
 * The Class MethodWriter, hols methods that write a method to a file.
 */
public abstract class MethodWriterHelper {

    /** The argument separator. */
    private static final String ARGUMENT_SEPARATOR = COMMA + SPACE_CHARACTER;

    /** The closer characters for a method. */
    private static final String METHOD_LINE_CLOSE = CLOSE_PARENTHESES
            + SPACE_CHARACTER + OPEN_CURLY_BRACKET;

    /**
     * Writes a method declaration.
     * 
     * @param writer
     *            the writer for the file
     * @param access
     *            the access level of the method, null for none
     * @param returnType
     *            the return type of the method, null for void
     * @param methodName
     *            the method name
     * @param args
     *            the the arguments of the method, one element per entry
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    protected static void openMethodDeclaration(Writer writer, String access,
            String returnType, String methodName, String[] args)
            throws IOException {

        Integer i = 0;
        StringBuilder sb = new StringBuilder(TAB_CHARACTER);

        if (access != null) {
            sb.append(access + SPACE_CHARACTER);
        }
        if (returnType != null) {
            sb.append(returnType + SPACE_CHARACTER);
        }
        sb.append(methodName + OPEN_PARENTHESES);

        if (args != null) {
            for (i = 0; i < args.length - 1; i++) {
                sb.append(args[i] + ARGUMENT_SEPARATOR);
            }
            sb.append(args[i]);
        }

        sb.append(METHOD_LINE_CLOSE);

        writer.write(sb.toString());
    }

    /**
     * Writes a public method declaration.
     * 
     * @param writer
     *            the writer for the file
     * @param returnType
     *            the return type of the method, null for void
     * @param methodName
     *            the method name
     * @param args
     *            the the arguments of the method, one element per entry
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    public static void openPublicMethodDeclaration(Writer writer,
            String returnType, String methodName, String[] args)
            throws IOException {
        openMethodDeclaration(writer, PUBLIC, returnType, methodName, args);
    }

    /**
     * Writes private method declaration.
     * 
     * @param writer
     *            the writer for the file
     * @param returnType
     *            the return type of the method, null for void
     * @param methodName
     *            the method name
     * @param args
     *            the the arguments of the method, one element per entry
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    public static void openPrivateMethodDeclaration(Writer writer,
            String returnType, String methodName, String[] args)
            throws IOException {
        openMethodDeclaration(writer, PRIVATE, returnType, methodName, args);
    }

    /**
     * Write protected method declaration.
     * 
     * @param writer
     *            the writer
     * @param returnType
     *            the return type of the method, null for void
     * @param methodName
     *            the method name
     * @param args
     *            the the arguments of the method, one element per entry
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    public static void openProtectedMethodDeclaration(Writer writer,
            String returnType, String methodName, String[] args)
            throws IOException {
        openMethodDeclaration(writer, PROTECTED, returnType, methodName, args);
    }

    /**
     * Writes a method declaration without an access level.
     * 
     * @param writer
     *            the writer for the file
     * @param returnType
     *            the return type of the method, null for void
     * @param methodName
     *            the method name
     * @param args
     *            the the arguments of the method, one element per entry
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    public static void openNothingMethodDeclaration(Writer writer,
            String returnType, String methodName, String[] args)
            throws IOException {
        openMethodDeclaration(writer, null, returnType, methodName, args);
    }

    /**
     * Closes a method declaration.
     * 
     * @param writer
     *            the writer for the file
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    public static void closeMethodDeclaration(Writer writer) throws IOException {
        writer.write(CLOSE_CURLY_BRACKET);
    }

    /**
     * Write a line of the method body.
     * 
     * @param writer
     *            the writer
     * @param bodyLine
     *            the body line
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    public static void writeMethodBody(Writer writer, String bodyLine)
            throws IOException {
        StringBuilder sb = new StringBuilder();
        sb.append(DOUBLE_TAB_CHARACTER);
        sb.append(bodyLine);
        if (!bodyLine.endsWith(";")) {
            sb.append(";");
        }
        writer.write(sb.toString());
    }

    /**
     * Writes the method body.
     * 
     * @param writer
     *            the writer for the file
     * @param bodyLines
     *            the lies of the body of the method
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    public static void writeMethodBody(Writer writer, String[] bodyLines)
            throws IOException {
        for (String bodyLine : bodyLines) {
            MethodWriterHelper.writeMethodBody(writer, bodyLine);
            writer.write(NEWLINE_CHARACTER);
        }
    }
}
